package com.ctc;

public class CTCMaster extends CTCDevice
{
    /**
     * 构造函数
     *
     * @param serialName 串口名称
     * @param productID  产品ID
     * @param deviceID   设备ID
     */
    public CTCMaster(String serialName, long productID, byte[] deviceID)
    {
        super((byte) 0, serialName, 38400);
        masterDeviceId = deviceID;
        masterProductId = productID;
        masterCTCVersion = CTC_MASTER_VERSION;
    }

    /**
     * 获取主设备状态
     *
     * @return 主设备状态
     */
    public byte getMasterState()
    {
        return masterState;
    }

    /**
     * 设置监听
     *
     * @param listener 监听
     */
    public void setListener(CTCEvent.IMaster listener)
    {
        this.listener = listener;
    }

    @Override
    public void open()
    {
        super.open();
        if (serialConnected)
        {
            sendHandshake();
        }
    }

    @Override
    protected void handleTimeOut()
    {
        if (handshake)
        {
            sendHeartbeat();
        }
        else
        {
            sendHandshake();
        }
    }

    @Override
    protected void handleOnSendFail(byte ackState, DataPacket dataPacket)
    {
        if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_HANDSHAKE))
        {
            logE("握手发送失败,10秒后重试中");
            reconnectNumber++;
        }
        else
        {
            super.handleOnSendFail(ackState, dataPacket);
        }
    }

    @Override
    protected void handleReceive(DataPacket dataPacket)
    {

        if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_HANDSHAKE_RSP))
        {//握手应答
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_HANDSHAKE_RSP)
            {
                logE(String.format("CTC Handshake Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            handshake = true;
            reconnectNumber = 0;
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnConnectStateChange(CTCClientConnState.Connected);
            slaveCTCVersion = CRC.bytesToUint16(dataPacket.getData()[20], dataPacket.getData()[21]);
            handleOnHandshake(dataPacket.getData());
            return;
        }
        //如果没有完成握手就不处理其它指令
        if (!handshake)
        {
            return;
        }
        if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_HEARTBEAT_RSP))
        {//心跳应答
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_HEARTBEAT_RSP)
            {
                logE(String.format("CTC Heartbeat Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            byte slaveState = dataPacket.getData()[0];
            int slaveError = CRC.bytesToUint16(dataPacket.getData()[1], dataPacket.getData()[2]);
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            if (this.slaveState != slaveState || this.slaveErrorCode != slaveError)
            {
                this.slaveState = slaveState;
                this.slaveErrorCode = slaveError;
                handleOnSlaveStateChange(dataPacket.getData());
            }
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_METER_DATA))
        {//读表应答
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_METER_DATA_RSP)
            {
                logE(String.format("CTC Meter Data Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnMeterData(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_COIN_IN_RSP))
        {//投币结果
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_COIN_IN_RSP)
            {
                logE(String.format("CTC Coin In Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnCoinInRsp(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_QUERY_COIN_RSP))
        {//查询单价结果
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_QUERY_COIN)
            {
                logE(String.format("CTC Query Coin Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnQueryCoin(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_ATMOSPHEREEVENT))
        {//氛围灯事件
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_ATMOSPHERE_EVENT)
            {
                logE(String.format("CTC Atmosphere Event Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;

            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnAtmosphere(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_REWARD))
        {//游戏奖励
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_REWARD)
            {
                logE(String.format("CTC Game Reward Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnReward(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_PHYSICAL_REPORT))
        {//实物奖励结果
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_PHYSICAL_REPORT)
            {
                logE(String.format("CTC Physical Report Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnPhysicalReport(dataPacket.getData());
        }
        else
        {
            // 不支持的指令
            sendACK(dataPacket, CTCMsg.CTC_ACK_UNSUPPORTED);
        }
    }

    /**
     * 发送握手
     */
    protected void sendHandshake()
    {
        logI("发送握手");
        byte[] data = new byte[22];
        System.arraycopy(CRC.uint32ToBytes(masterProductId), 0, data, 0, 4);
        System.arraycopy(masterDeviceId, 0, data, 4, 16);
        System.arraycopy(CRC.uint16ToBytes(masterCTCVersion), 0, data, 20, 2);
        send(new DataPacket(player, CTCMsg.CTC_CMD_HANDSHAKE, sendTransactionId++, data));
    }

    /**
     * 发送抄表指令
     */
    public void sendReadMeter()
    {
        send(new DataPacket(player, CTCMsg.CTC_CMD_METER_READ, sendTransactionId++, null));
    }

    @Override
    protected void sendHeartbeat()
    {
        if (deviceConnState == CTCClientConnState.Connected)
        {
            logI("发送心跳");
            send(new DataPacket(player, CTCMsg.CTC_CMD_HEARTBEAT, sendTransactionId++, masterState));
        }
    }

    /**
     * 发送投币指令
     *
     * @param number   投币数量	4字节	投币数量
     * @param memberID 会员ID	16字节	同一张会员卡或同一个会员账户时ID相同
     * @param orderNo  消费记录ID	16字节	标识此笔交易的ID
     */
    public void sendInCoin(long number, byte[] memberID, byte[] orderNo)
    {
        byte[] data = new byte[36];
        System.arraycopy(CRC.uint32ToBytes(number), 0, data, 0, 4);
        System.arraycopy(memberID, 0, data, 4, 16);
        System.arraycopy(orderNo, 0, data, 20, 16);
        send(new DataPacket(player, CTCMsg.CTC_CMD_COIN_IN, sendTransactionId++, data));
    }

    /**
     * 发送通道选择指令
     *
     * @param c0 彩票通道	0=实物,1=电子,2=暂时不出
     * @param c1 蓝票通道	0=实物,1=电子,2=暂时不出
     */
    public void sendSelectChannel(byte c0, byte c1)
    {
        send(new DataPacket(player, CTCMsg.CTC_CMD_CHANNEL_SEL, sendTransactionId++, c0, c1));
    }

    /**
     * 发送查询每局币数指令
     */
    public void sendQueryCoinPrice()
    {
        send(new DataPacket(player, CTCMsg.CTC_CMD_QUERY_COIN, sendTransactionId++, null));
    }

    /**
     * 发送设置每局币数指令
     *
     * @param number 每局币数
     */
    public void sendSetCoinPrice(int number)
    {
        send(new DataPacket(player, CTCMsg.CTC_CMD_SET_COIN, sendTransactionId++, CRC.uint16ToBytes(number)));
    }

    /**
     * 发送变更状态指令
     *
     * @param state 0=正常可用,1=等待配网,2=连接门店服务异常,3=网络无法连接,4=正在联网
     */
    public void changeState(byte state)
    {
        masterState = state;
        sendHeartbeat();
    }

    /**
     * 处理连接状态变化
     *
     * @param data 连接状态数据
     */
    protected void handleOnSlaveStateChange(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onSlaveStateChange(player, data);
        }
    }

    /**
     * 处理读表数据
     *
     * @param data 读表数据
     */
    protected void handleOnMeterData(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onMeterData(player, data);
        }
    }

    /**
     * 处理实物奖励结果
     *
     * @param data 实物奖励结果数据
     */
    protected void handleOnPhysicalReport(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onPhysicalReport(player, data);
        }
    }

    /**
     * 处理查询每局币数结果
     *
     * @param data 查询每局币数结果数据
     */
    protected void handleOnQueryCoin(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onQueryCoin(player, data);
        }
    }

    /**
     * 处理氛围灯事件
     *
     * @param data 氛围灯事件数据
     */
    protected void handleOnAtmosphere(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onAtmosphere(player, data);
        }
    }

    /**
     * 处理握手事件
     *
     * @param data 握手事件数据
     */
    protected void handleOnHandshake(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onHandshake(player, data);
        }
    }

    /**
     * 处理投币结果事件
     *
     * @param data 投币结果事件数据
     */
    protected void handleOnCoinInRsp(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onCoinInRsp(player, data);
        }
    }

    /**
     * 处理游戏奖励事件
     *
     * @param data 游戏奖励事件数据
     */
    protected void handleOnReward(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.IMaster) listener).onReward(player, data);
        }
    }

}
